import 'package:flutter/material.dart';
import 'dart:math';

class CircleSlider extends StatefulWidget {
  final double initialValue;
  final ValueChanged<double>? onChanged;
  final Color activeColor;
  final Color inactiveColor;
  final double strokeWidth;
  final double thumbSize;
  final Color? thumbColor;
  final Color? thumbBorderColor;
  final double thumbBorderWidth;
  final Color? overlayColor;
  final double overlayRadius;

  const CircleSlider({
    Key? key,
    this.initialValue = 0,
    this.onChanged,
    this.activeColor = Colors.green,
    this.inactiveColor = Colors.orange,
    this.strokeWidth = 20,
    this.thumbSize = 10,
    this.thumbColor,
    this.thumbBorderColor = Colors.white,
    this.thumbBorderWidth = 2,
    this.overlayColor,
    this.overlayRadius = 24,
  }) : super(key: key);

  @override
  State<CircleSlider> createState() => _CircleSliderState();
}

class _CircleSliderState extends State<CircleSlider> {
  late double _value;
  bool _isDragging = false;
  double _lastAngle = 0;

  @override
  void initState() {
    super.initState();
    _value = widget.initialValue;
  }

  void _updateValue(Offset position, BoxConstraints constraints) {
    final center = Offset(constraints.maxWidth / 2, constraints.maxHeight / 2);
    final radius = min(constraints.maxWidth, constraints.maxHeight) / 2;

    final distance = (position - center).distance;
    if (distance > radius) {
      return;
    }

    final angle = atan2(
      position.dy - center.dy,
      position.dx - center.dx,
    );

    var degrees = (angle * 180 / pi + 360) % 360;
    degrees = (degrees + 90) % 360;

    if (_isDragging) {
      final angleDiff = degrees - _lastAngle;
      if (angleDiff > 180) {
        return;
      } else if (angleDiff < -180) {
        return;
      }
    }

    _lastAngle = degrees;

    var newValue = (degrees / 360) * 100;
    newValue = newValue.clamp(0, 100);

    if (newValue != _value) {
      setState(() {
        _value = newValue;
      });
      widget.onChanged?.call(_value);
    }
  }

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(
      builder: (context, constraints) {
        return GestureDetector(
          onPanStart: (details) {
            _isDragging = true;
            _updateValue(details.localPosition, constraints);
          },
          onPanUpdate: (details) {
            if (_isDragging) {
              _updateValue(details.localPosition, constraints);
            }
          },
          onPanEnd: (_) {
            _isDragging = false;
          },
          child: CustomPaint(
            size: Size(constraints.maxWidth, constraints.maxHeight),
            painter: CircleSliderPainter(
              value: _value,
              activeColor: widget.activeColor,
              inactiveColor: widget.inactiveColor,
              strokeWidth: widget.strokeWidth,
              thumbSize: widget.thumbSize,
              thumbColor: widget.thumbColor ?? widget.activeColor,
              thumbBorderColor: widget.thumbBorderColor ?? Colors.transparent,
              thumbBorderWidth: widget.thumbBorderWidth,
              overlayColor:
              widget.overlayColor ?? widget.activeColor.withOpacity(0.2),
              overlayRadius: widget.overlayRadius,
            ),
          ),
        );
      },
    );
  }
}

class CircleSliderPainter extends CustomPainter {
  final double value;
  final Color activeColor;
  final Color inactiveColor;
  final double strokeWidth;
  final double thumbSize;
  final Color thumbColor;
  final Color thumbBorderColor;
  final double thumbBorderWidth;
  final Color overlayColor;
  final double overlayRadius;

  CircleSliderPainter({
    required this.value,
    required this.activeColor,
    required this.inactiveColor,
    required this.strokeWidth,
    required this.thumbSize,
    required this.thumbColor,
    required this.thumbBorderColor,
    required this.thumbBorderWidth,
    required this.overlayColor,
    required this.overlayRadius,
  });

  @override
  void paint(Canvas canvas, Size size) {
    final center = Offset(size.width / 2, size.height / 2);
    final radius = min(size.width, size.height) / 2;

    // Draw inactive arc
    final inactivePaint = Paint()
      ..color = inactiveColor
      ..style = PaintingStyle.stroke
      ..strokeWidth = strokeWidth
      ..strokeCap = StrokeCap.round;

    canvas.drawCircle(center, radius - strokeWidth / 2, inactivePaint);

    // Draw active arc
    final activePaint = Paint()
      ..color = activeColor
      ..style = PaintingStyle.stroke
      ..strokeWidth = strokeWidth
      ..strokeCap = StrokeCap.round;

    final activeRect =
    Rect.fromCircle(center: center, radius: radius - strokeWidth / 2);
    final sweepAngle = 2 * pi * (value / 100);
    canvas.drawArc(
      activeRect,
      -pi / 2,
      sweepAngle,
      false,
      activePaint,
    );

    // Draw thumb
    final thumbAngle = -pi / 2 + sweepAngle;
    final thumbCenter = Offset(
      center.dx + (radius - strokeWidth / 2) * cos(thumbAngle),
      center.dy + (radius - strokeWidth / 2) * sin(thumbAngle),
    );

    // Draw thumb overlay
    final overlayPaint = Paint()
      ..color = overlayColor
      ..style = PaintingStyle.fill;

    canvas.drawCircle(thumbCenter, overlayRadius, overlayPaint);

    // Draw main thumb
    final thumbPaint = Paint()
      ..color = thumbColor
      ..style = PaintingStyle.fill;

    // Draw thumb border
    final thumbBorderPaint = Paint()
      ..color = thumbBorderColor
      ..style = PaintingStyle.stroke
      ..strokeWidth = thumbBorderWidth;

    // Draw the thumb with border
    canvas.drawCircle(thumbCenter, thumbSize, thumbPaint);
    canvas.drawCircle(thumbCenter, thumbSize, thumbBorderPaint);
  }

  @override
  bool shouldRepaint(CircleSliderPainter oldDelegate) {
    return oldDelegate.value != value ||
        oldDelegate.activeColor != activeColor ||
        oldDelegate.inactiveColor != inactiveColor ||
        oldDelegate.strokeWidth != strokeWidth ||
        oldDelegate.thumbSize != thumbSize ||
        oldDelegate.thumbColor != thumbColor ||
        oldDelegate.thumbBorderColor != thumbBorderColor ||
        oldDelegate.thumbBorderWidth != thumbBorderWidth ||
        oldDelegate.overlayColor != overlayColor ||
        oldDelegate.overlayRadius != overlayRadius;
  }
}
